package com.song.gateway.filter;


import com.song.utils.RedisOperator;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.cloud.gateway.filter.GatewayFilterChain;
import org.springframework.cloud.gateway.filter.GlobalFilter;
import org.springframework.core.Ordered;
import org.springframework.http.HttpStatus;
import org.springframework.http.server.reactive.ServerHttpRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.server.ServerWebExchange;
import reactor.core.publisher.Mono;

/**
 * 构建gateway的自定义过滤器
 */
@Component
public class BlackIPFilter implements GlobalFilter, Ordered {

    @Autowired
    private RedisOperator redis;

    @Value("${blackIp.continueCounts}")
    private Integer continueCounts;

    @Value("${blackIp.timeInterval}")
    private Integer timeInterval;

    @Value("${blackIp.limitTimes}")
    private Integer limitTimes;

    @Override
    public Mono<Void> filter(ServerWebExchange exchange, GatewayFilterChain chain) {

        System.out.println("执行【ip黑名单】gateway过滤器...");
        System.out.println("continueCounts: " + continueCounts);
        System.out.println("timeInterval: " + timeInterval);
        System.out.println("limitTimes: " + limitTimes);

        // 获取上下文对象requestContext
        ServerHttpRequest serverHttpRequest = exchange.getRequest();
        // 获取ip
        String ip = getIP(serverHttpRequest);

        /**
         * 需求：
         * 判断ip在10秒内请求的次数超过10次
         * 如果超过，则限制访问15秒，15秒过后解除
         */
        final String ipRedisKey = "gateway-ip" + ip;
        final String ipRedisLimitKey = "gateway-ip-limit" + ip;

        // 获取剩余的限制时间
        long limitLeftTime = redis.ttl(ipRedisLimitKey);
        // 如果时间还存在，说明这个ip还不能访问，继续等待
        if (limitLeftTime > 0) {
            return stopRequest(exchange);
        }

        // 在redis中累加ip请求访问次数
        long requestCounts = redis.increment(ipRedisKey, 1);

        // 从0开始计算请求次数，初期访问为1，则设置过期时间，也就是连续访问请求的间隔时间
        if (requestCounts == 1) {
            redis.expire(ipRedisKey, timeInterval);
        }

        // 如果还能获取请求次数，说明用户连续请求的次数落在10秒内
        // 一旦请求次数超过了连续访问次数，则需要限制这个ip
        if (requestCounts > continueCounts) {
            // 限制ip访问一段时间
            redis.set(ipRedisLimitKey, ipRedisLimitKey, limitTimes);
            return stopRequest(exchange);
        }

        return chain.filter(exchange);
    }

    private String getIP(ServerHttpRequest request){
        // 根据 HttpHeaders 获取 请求 IP地址
        String ip = request.getHeaders().getFirst("X-Forwarded-For");
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeaders().getFirst("Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeaders().getFirst("WL-Proxy-Client-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeaders().getFirst("HTTP_CLIENT_IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeaders().getFirst("HTTP_X_FORWARDED_FOR");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getHeaders().getFirst("X-Real-IP");
        }
        if (ip == null || ip.length() == 0 || "unknown".equalsIgnoreCase(ip)) {
            ip = request.getRemoteAddress().getHostString();
        }
        return ip;
    }

    private Mono<Void> stopRequest(ServerWebExchange exchange) {
        // 禁止通行，禁止向下继续路由
        exchange.getResponse().setStatusCode(HttpStatus.BAD_GATEWAY);
        return exchange.getResponse().setComplete();
    }

    @Override
    public int getOrder() {
        return 1;
    }
}
